/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package rippledemo;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.awt.image.MemoryImageSource;
import java.awt.image.PixelGrabber;
import javax.swing.JPanel;

/**
 *
 * @author WIN7
 */
public class RipplePanel extends JPanel implements MouseListener, MouseMotionListener, Runnable{

    private Thread run_thread;
    private boolean is_thread_running;
    private boolean is_pause;
    private String background_image_path;
    private Image background_image;


    int image_width,image_height,half_width,half_height;
    MemoryImageSource source_image;
    Image display_image, offImage;
    Graphics offGraphics;
    int i,a,b;
    int MouseX,MouseY;
    int size;

    short ripplemap[];
    int texture[];
    int ripple[];
    int oldind,newind,mapind;
    int riprad;


    int frame_count = 0, FPS = 0;
    long frame_count_start_time = 0;
    
    public RipplePanel(){
        
    }

    public void init(){
        run_thread = new Thread(this);
        is_thread_running = true;
        is_pause = false;
        run_thread.start();
        addMouseMotionListener(this);
        addMouseListener(this);
        background_image_path = "res/paint.jpg";
        MediaTracker mt = new MediaTracker(this);
        background_image = getToolkit().getImage(background_image_path);
        mt.addImage(background_image,0);
        try {
            mt.waitForID(0);
        } catch (InterruptedException e) {
            return;
        }
        image_width = background_image.getWidth(this);
        image_height = background_image.getHeight(this);
        half_width = image_width>>1;
        half_height = image_height>>1;
        riprad=3;
        size = image_width * (image_height+2) * 2;
        ripplemap = new short[size];
//        System.out.println("ripplemap[0] == " + ripplemap[0]);
        ripple = new int[image_width*image_height];
        texture = new int[image_width*image_height];
        oldind = image_width;
        newind = image_width * (image_height+3);

        PixelGrabber pg = new PixelGrabber(background_image,0,0,image_width,image_height,texture,0,image_width);
        try {
        pg.grabPixels();
        } catch (InterruptedException e) {}
        source_image = new MemoryImageSource(image_width, image_height, ripple, 0, image_width);
        source_image.setAnimated(true);
        source_image.setFullBufferUpdates(true);

        display_image = createImage(source_image);
        offImage = new BufferedImage(image_width, image_height, BufferedImage.TYPE_INT_ARGB);
        offGraphics = offImage.getGraphics();
        
    }
    
    @Override
    public void paint(Graphics g){
        if(!is_pause){
            newframe();
            source_image.newPixels();
            offGraphics.drawImage(display_image,0,0,image_width,image_height,null);
            g.drawImage(offImage, 0, 0, this);
        }else{
            g.drawString("Paused", 5, 15);
        }
        g.drawString("FPS: " + FPS, getWidth() - 50, 15);
    }

    

    public void run(){
        while(is_thread_running){
                if(System.currentTimeMillis() - frame_count_start_time < 1000){
                        frame_count ++;
                }else{
                        FPS = frame_count;
                        frame_count = 0;
                        frame_count_start_time = System.currentTimeMillis();
                }
                repaint();
        }
    }

    //Custom function

    public void disturb(int mouse_x, int mouse_y) {
      for (int j=mouse_y-riprad;j<mouse_y+riprad;j++) {
        for (int k=mouse_x-riprad;k<mouse_x+riprad;k++) {
          if (j>=0 && j<image_height && k>=0 && k<image_width) {
	    ripplemap[oldind+(j*image_width)+k] += 512;
          }
        }
      }
    }

    public void newframe() {
      //Toggle maps each frame
      i=oldind;
      oldind=newind;
      newind=i;

      i=0;
      mapind=oldind;
//      System.out.println("new frame");
//      System.out.println("i = " + i);
//      System.out.println("oldind = " + oldind);
//      System.out.println("newind = " + newind);
//      System.out.println("mapind = " + mapind);
//      System.out.println("size = " + size);

      for (int y=0;y<image_height;y++) {
        for (int x=0;x<image_width;x++) {
	  short data = (short)((ripplemap[mapind-image_width]+ripplemap[mapind+image_width]+ripplemap[mapind-1]+ripplemap[mapind+1])>>1);
          data -= ripplemap[newind+i];
          data -= data >> 5;
          ripplemap[newind+i]=data;

	  //where data=0 then still, where data>0 then wave
	  data = (short)(1024-data);

          //offsets
  	  a=((x-half_width)*data/1024)+half_width;
          b=((y-half_height)*data/1024)+half_height;

          
 	  //bounds check
          if (a>=image_width) a=image_width-1;
          if (a<0) a=0;
          if (b>=image_height) b=image_height-1;
          if (b<0) b=0;
          

          ripple[i]=texture[a+(b*image_width)];          
          mapind++;
	  i++;
        }
      }
    }

    public void mouseDragged(MouseEvent e) {
        
    }

    public void mouseMoved(MouseEvent e) {
        disturb(e.getX(),e.getY());
    }

    public void mouseClicked(MouseEvent e) {
        if(e.getButton() == MouseEvent.BUTTON1){
            disturb(e.getX(),e.getY());
        }else{
            is_pause = !is_pause;
        }
    }

    public void mousePressed(MouseEvent e) {
        
    }

    public void mouseReleased(MouseEvent e) {
        
    }

    public void mouseEntered(MouseEvent e) {
        
    }

    public void mouseExited(MouseEvent e) {
        
    }

}
